/*
 * LogFactory.c
 *
 *  Created on: 19.09.2011
 *      Author: sili
 */

#include "LogFactory.h"

static log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("at.sili.aalsystem.factories.LogFactory"));

static struct logMessage logMessages[MAX_LOG_MESSAGES];	//Ringbuffer
static long lastLogMessageId;
static pthread_rwlock_t logFactoryLock = PTHREAD_RWLOCK_INITIALIZER;

LogFactory::LogFactory(Controller * _controller, const char * _configDir)
	: ActionListener("LogFactory"){

	this->configDir.clear();
	this->configDir.append(_configDir);
	this->configDir.append("/logs");

	this->controller = _controller;
	this->controller->addListener(this);

	this->propertyFile.clear();
	this->propertyFile.append(_configDir);
	this->propertyFile.append("/log4cxx.properties");

	// check if the logs directory exists
	char * targetName = canonicalize_file_name(this->configDir.c_str());
	if(!targetName){
		// directory doesn't exists
		AAL_INFO(logger, "Directory %s doesn't exists. Creating a new one", this->configDir.c_str());
		mkdir(this->configDir.c_str(), 0777);
	}
	delete(targetName);

	// check if an properties.xml file exists
	targetName = canonicalize_file_name(propertyFile.c_str());
	if(!targetName){
		// file doesn't exists
		AAL_INFO(logger, "File: %s doesn't exists. Creating a new one.", propertyFile.c_str());

		ofstream logPropertyFile;
		logPropertyFile.open(this->propertyFile.c_str());
		logPropertyFile << "log4j.rootLogger=debug, stdout, R\n\n"
				"log4j.appender.stdout=org.apache.log4j.ConsoleAppender\n"
				"log4j.appender.stdout.layout=org.apache.log4j.PatternLayout\n"
				"log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n\n\n"
				"log4j.appender.R=org.apache.log4j.RollingFileAppender\n"
				"log4j.appender.R.File=" << this->configDir.c_str() << "/vdr4aal.log\n"
				"log4j.appender.R.MaxFileSize=1000KB\n"
				"log4j.appender.R.MaxBackupIndex=10\n"
				"log4j.appender.R.layout=org.apache.log4j.PatternLayout\n"
				"log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n\n";
		logPropertyFile.close();
	}

	//log4cxx::BasicConfigurator::configure();
	log4cxx::PropertyConfigurator::configure(targetName);
	AAL_DEBUG(logger, "Using log configuration file %s", targetName);
	delete(targetName);
}

LogFactory::~LogFactory(){
	AAL_DEBUG(logger, "Destructor");
}

char * LogFactory::logMsg2json(const struct logMessage * _message){
	char buf[sizeof(logMessages[0])];  // Large enough to hold one httpMessage
	int len = 0;
	len += snprintf(buf + len, sizeof(buf) - len,
		"{\"id\": \"%lu\", \"status\": \"%s\", \"message\": \"%s\", \"timestamp\": \"%lu\"}",
		_message->id, _message->status, _message->text, _message->timestamp);
	return len == 0 ? NULL : strdup(buf);
}

char * LogFactory::logMsg2xml(const struct logMessage * _message) {
	char buf[sizeof(logMessages[0])];
	int len = 0;
	len += snprintf(buf + len, sizeof(buf) - len,
			"<message \"id\": \"%lu\", \"status\": \"%s\", \"message\": \"%s\", \"timestamp\": \"%lu\" />",
			_message->id, _message->status, _message->text, _message->timestamp);
	return len == 0 ? NULL : strdup(buf);
}

logMessage * LogFactory::newLogMessage(logMsgStatus _status, const char * _message) {
	static int size = sizeof(logMessages) / sizeof(logMessages[0]);
	struct logMessage * message = &logMessages[lastLogMessageId % size];
	message->id = lastLogMessageId++;
	message->timestamp = time(0);
	switch(_status){
		case trace:
			Tools::stringCopy(message->status, "TRACE", sizeof(message->status) - 1);
			break;
		case debug:
			Tools::stringCopy(message->status, "DEBUG", sizeof(message->status) - 1);
			break;
		case info:
			Tools::stringCopy(message->status, "INFO", sizeof(message->status) - 1);
			break;
		case warn:
			Tools::stringCopy(message->status, "WARN", sizeof(message->status) - 1);
			break;
		case error:
			Tools::stringCopy(message->status, "ERROR", sizeof(message->status) - 1);
			break;
		default:
			Tools::stringCopy(message->status, "FATAL", sizeof(message->status) - 1);
	}
	Tools::stringCopy(message->text, _message, sizeof(message->text) - 1);
	return message;
}

void LogFactory::logMsgs2json(long last_id, string * _buffer) {
	const struct logMessage * message;
	int max_msgs;

	// Read-lock the ringbuffer. Loop over all httpMessages, making a JSON string.
	pthread_rwlock_rdlock(&logFactoryLock);
	max_msgs = sizeof(logMessages) / sizeof(logMessages[0]);

	// If client is too far behind, return all httpMessages.
	if (lastLogMessageId - last_id > max_msgs) {
		last_id = lastLogMessageId - max_msgs;
	}

	_buffer->append("[");
	for (; last_id < lastLogMessageId; last_id++) {
		message = & logMessages[last_id % max_msgs];
		if (message->timestamp == 0) {
			break;
		}

		char * singleJson = logMsg2json(message);
		if(singleJson != NULL){
			_buffer->append(singleJson);
			if(last_id + 1 < lastLogMessageId)
				_buffer->append(",");
		}
	}
	_buffer->append("]\n");
	pthread_rwlock_unlock(&logFactoryLock);
}
